package edu.xhu.video.util;

import edu.xhu.model.behavior.vo.CommentTree;
import edu.xhu.model.common.constants.CommentConstants;

import java.util.*;

public class CommentTreeBuilder {

    /**
     * 构建单个视频的评论树，根评论按照热度或时间排序，子评论按照时间排序
     *
     * @param rootCommentMaplist  视频的多个根评论信息，局部有序(热度/时间)，函数内部会做排序
     * @param sonCommentMaplist   视频的多个子评论信息，局部有序(时间)，需要外部输入保证时间顺序，函数内部不额外做排序
     * @param userInfoMapList     视频评论(根评论，子评论)所涉及的用户信息
     * @param rootCommentSortType 根评论排序类型：热度/时间
     * @return
     */
    public static List<CommentTree> buildCommentTree(List<Map> rootCommentMaplist,
                                                     List<Map> sonCommentMaplist,
                                                     List<Map> userInfoMapList,
                                                     String rootCommentSortType) {
        List<CommentTree> commentTrees = null; //最终结果集

        //0. 种树前准备
        //0.1 准备用户信息查找map, {userId=userInfoMap, ..., userId=userInfoMap}
        Map<Long, Map<String, Object>> userInfoByIdMap = new HashMap<>();
        userInfoMapList.forEach(map -> {
            if (map.containsKey("user_id"))
                userInfoByIdMap.put((Long) map.get("user_id"), map);
        });

        //1. 将子评论封装至对应根评论的 replies
        //根评论树之Map，{rootCommentId=rootCommentTree,...,}, 这里的rootCommentTree是根评论
        Map<Long, CommentTree> rootComments = new HashMap<>();

        //1.1 先构建根评论的CommentTree,遍历所有根评论信息
        rootCommentMaplist.forEach(map -> {
            CommentTree rootComment = new CommentTree();

            // 将map中的 kv 复制到根评论对应的属性
            CommentTreeUtil.copyMapToCommentBeanProperties(map, rootComment);
            // 补充rootComment其他属性
            rootComment.setUserAllInfo(userInfoByIdMap.get(rootComment.getUserId()));
            if (rootComment.getReplies() == null)
                rootComment.setReplies(new ArrayList<>());

            rootComments.put(rootComment.getCommentId(), rootComment);
        });

        //1.2 将子评论组装至根评论的 replies, 一定要按顺序遍历子评论，保证 replies 里面子评论之间的时间顺序
        if (sonCommentMaplist != null)
            sonCommentMaplist.forEach(map -> {
                CommentTree sonComment = new CommentTree();

                //将map中的 kv 复制到子评论对应的属性
                CommentTreeUtil.copyMapToCommentBeanProperties(map, sonComment);
                // 补充sonComment其他属性
                sonComment.setUserAllInfo(userInfoByIdMap.get(sonComment.getUserId()));
                sonComment.setToUserAllInfo(userInfoByIdMap.get(sonComment.getToUserId()));

                if (rootComments.containsKey(sonComment.getRootId())) {
                    rootComments.get(sonComment.getRootId()).getReplies().add(sonComment);
                }
            });

        //2. 开始打包最终结果
        commentTrees = new ArrayList<>(rootComments.values());

        //3. 对根评论进行排序
        //根据热度/时间排序
        if (rootCommentSortType != null && rootCommentSortType.equals(CommentConstants.ROOT_COMMENT_SORT_BY_HOTNESS))
            Collections.sort(commentTrees, Comparator.comparingDouble(CommentTree::getScore).reversed());
        else if (rootCommentSortType != null && rootCommentSortType.equals(CommentConstants.ROOT_COMMENT_SORT_BY_TIME))
            Collections.sort(commentTrees, Comparator.comparing(CommentTree::getCreateTime).reversed());

        return commentTrees;
    }


    /**
     * (一次性组装多个视频的多个评论树)
     * 构建视频的评论树，根评论按照热度或时间排序，子评论按照时间排序
     *
     * @param videoIds            视频id
     * @param rootCommentMaplist  所有视频的根评论信息，局部有序(热度/时间)，函数内部会做排序
     * @param sonCommentMaplist   所有视频的子评论信息，局部有序(时间)，需要外部输入保证时间顺序，函数内部不额外做排序
     * @param userInfoMapList     所有视频评论(根评论，子评论)所涉及的用户信息
     * @param rootCommentSortType 根评论排序类型：热度/时间
     * @return {videoid=根评论数组(根评论有序) , ..., }
     */
    public static Map<Long, List<CommentTree>> buildCommentTree(List<Long> videoIds,
                                                                List<Map> rootCommentMaplist,
                                                                List<Map> sonCommentMaplist,
                                                                List<Map> userInfoMapList,
                                                                String rootCommentSortType) {
        // {videoid=根评论数组(根评论有序) , ..., videoid=根评论数组}
        Map<Long, List<CommentTree>> videoIdToCommentTreeMap = new HashMap<>(); //最终结果集

        //0. 种树前准备
        //0.1 准备用户信息查找map, {userId=userInfoMap, ..., userId=userInfoMap}
        Map<Long, Map<String, Object>> userInfoByIdMap = new HashMap<>();
        userInfoMapList.forEach(map -> {
            if (map.containsKey("user_id"))
                userInfoByIdMap.put((Long) map.get("user_id"), map);
        });

        //1. 将子评论封装至对应根评论的 replies
        //根评论树之Map，{rootCommentId=rootCommentTree,...,}, 这里的rootCommentTree是根评论
        Map<Long, CommentTree> rootComments = new HashMap<>();

        //1.1 先构建根评论的CommentTree,遍历所有根评论信息
        rootCommentMaplist.forEach(map -> {
            CommentTree rootComment = new CommentTree();

            // 将map中的 kv 复制到根评论对应的属性
            CommentTreeUtil.copyMapToCommentBeanProperties(map, rootComment);
            // 补充rootComment其他属性
            rootComment.setUserAllInfo(userInfoByIdMap.get(rootComment.getUserId()));
            if (rootComment.getReplies() == null)
                rootComment.setReplies(new ArrayList<>());

            rootComments.put(rootComment.getCommentId(), rootComment);
        });

        //1.2 将子评论组装至根评论的 replies, 一定要按顺序遍历子评论，保证 replies 里面子评论之间的时间顺序
        sonCommentMaplist.forEach(map -> {
            CommentTree sonComment = new CommentTree();

            //将map中的 kv 复制到子评论对应的属性
            CommentTreeUtil.copyMapToCommentBeanProperties(map, sonComment);
            // 补充sonComment其他属性
            sonComment.setUserAllInfo(userInfoByIdMap.get(sonComment.getUserId()));
            sonComment.setToUserAllInfo(userInfoByIdMap.get(sonComment.getToUserId()));

            if (rootComments.containsKey(sonComment.getRootId())) {
                rootComments.get(sonComment.getRootId()).getReplies().add(sonComment);
            }
        });


        //2. 组装最终结果集
        //2.1 将videoIds装进结果集
        videoIds.forEach(videoId -> {
            videoIdToCommentTreeMap.put(videoId, new ArrayList<CommentTree>());
        });

        //2.2 将根评论装进结果集
        //拿到所有的根评论，装进list
        List<CommentTree> rootCommentList = new ArrayList<>(rootComments.values());

        //根据热度/时间排序
        if (rootCommentSortType.equals(CommentConstants.ROOT_COMMENT_SORT_BY_HOTNESS))
            Collections.sort(rootCommentList, Comparator.comparingDouble(CommentTree::getScore).reversed());
        else
            Collections.sort(rootCommentList, Comparator.comparing(CommentTree::getCreateTime).reversed());

        // rootCommentList已经有序，一定要按顺序遍历组装
        rootCommentList.forEach(rootCommment -> {
            videoIdToCommentTreeMap.get(rootCommment.getVideoId()).add(rootCommment);
        });

        return videoIdToCommentTreeMap;
    }


}
